package models

import (
	"fmt"
	"strings"

	"github.com/astaxie/beego/logs"
	"github.com/astaxie/beego/orm"

	"cvevulner/common"
)

const splitLen = 2

// ExcelExport the export excel row content model
type ExcelExport struct {
	Num                int64
	CveNum             string  `json:"cve_num"`
	OpeneulerScore     float64 `json:"openeuler_score"`
	OpeneulerVector    string  `json:"openeuler_vector"`
	CveBrief           string  `json:"cve_brief"`
	OwnedComponent     string  `json:"owned_component"`
	SecID              int64   `json:"sec_id" orm:"column(sec_id)"`
	Introduction       string  `json:"introduction"`
	Summary            string  `json:"summary"`
	Theme              string  `json:"theme"`
	Description        string  `json:"description"`
	InfluenceComponent string  `json:"influence_component" orm:"size(256);null;column(influence_component)"`
	AffectProduct      string  `json:"affect_product"`
	ReferenceLink      string  `json:"reference_link"`
	AffectStatus       string  `json:"affect_status"`
	PublicDate         string  `json:"public_date"`
	OpenEulerSANum     string  `json:"openeuler_sa_num" orm:"size(128);column(openeuler_sa_num)"`
	CveLevel           string  `json:"cve_level" orm:"size(32);column(cve_level)"`
	OrganizateId       int8    `json:"organizate_id" orm:"column(organizate_id)"`
	AffectedVersion    string  `json:"affected_version" orm:"column(affected_version)"`
	AnalysisVersion    string  `json:"analysis_version" orm:"column(analysis_version)"`
	IssueLabel         string  `json:"issue_label" orm:"column(issue_label)"`
	Repo               string  `json:"repo" orm:"column(repo)"`
}

func (e ExcelExport) IsIssueWithAnalysisVersion() bool {
	return e.AnalysisVersion != ""
}

func (e ExcelExport) ParseAnalysisVersion() map[string]string {
	result := make(map[string]string)
	split := strings.Split(e.AnalysisVersion, ",")
	for _, v := range split {
		item := strings.Split(strings.ReplaceAll(v, "：", ":"), ":")
		if len(item) != splitLen {
			continue
		}

		result[item[0]] = item[1]
	}

	return result
}

func (e ExcelExport) GetReasonByVersion(v string) string {
	version := e.ParseAnalysisVersion()
	reason, ok := version[v]
	if ok {
		english, ok2 := common.AnalysisEnglishMap[reason]
		if ok2 {
			return english
		}
	}

	return ""
}

func (e ExcelExport) AffectType(v string) string {
	if !e.IsIssueWithAnalysisVersion() {
		return common.TypeUnaffected
	}

	for version, reason := range e.ParseAnalysisVersion() {
		if v == version {
			if reason == "" {
				return common.TypeUnderInvestigation
			}

			if _, ok := common.AnalysisUnaffected[reason]; ok {
				return common.TypeUnaffected
			}

			break
		}
	}

	return common.TypeAffected
}

// ExcelPackage Released packages
type ExcelPackage struct {
	PubTime  string
	Repo     string
	Packages string
}

// Insert Insert a generated excel file record
func (er ExportRecord) Insert() error {
	o := orm.NewOrm()
	_, err := o.Insert(&er)
	return err
}

// QueryLast query the last excel record
func (er *ExportRecord) QueryLast() error {
	o := orm.NewOrm()
	err := o.QueryTable(er).Filter("state", 0).OrderBy("-create_time").One(er)
	return err
}

// Update update by column name
func (er *ExportRecord) Update(field ...string) error {
	o := orm.NewOrm()
	_, err := o.Update(er, field...)
	return err
}

// Read read by column name
func (er *ExportRecord) Read(field ...string) error {
	o := orm.NewOrm()
	return o.Read(er, field...)
}

func (elt *EmailList) Read(field ...string) ([]EmailList, error) {
	o := orm.NewOrm()
	var el []EmailList
	var num int64
	num, err := o.Raw("select *"+
		" from cve_email_list where email_type = ?", elt.EmailType).QueryRows(&el)
	if err == nil && num > 0 {
		return el, nil
	}
	logs.Error("cve_email_list ,err: ", err)
	return el, err
}

func GetCvrfRecord(cfr *CvrfSaRecord, colName ...string) error {
	o := orm.NewOrm()
	err := o.Read(cfr, colName...)
	return err
}

func InsertCvrfRecord(cfr *CvrfSaRecord) (int64, error) {
	o := orm.NewOrm()
	num, err := o.Insert(cfr)
	return num, err
}

func UpdateCvrfRecord(cfr *CvrfSaRecord, fields ...string) error {
	o := orm.NewOrm()
	_, err := o.Update(cfr, fields...)
	return err
}

func GetCvrfFileName(afl *SaFileList, colName ...string) error {
	o := orm.NewOrm()
	err := o.Read(afl, colName...)
	return err
}

func GetCvrfAllFile(t string) []SaFileRecord {
	o := orm.NewOrm()
	var afl []SaFileRecord
	num, err := o.Raw("SELECT * FROM cve_sa_file_record where sa_type = ? order by file_id asc", t).QueryRows(&afl)
	if err == nil {
		logs.Info("cve_sa_file_record nums: ", num)
	} else {
		logs.Error("cve_sa_file_record, err: ", err)
	}
	return afl
}

func InsertCvrfFileName(afl *SaFileList) (int64, error) {
	o := orm.NewOrm()
	num, err := o.Insert(afl)
	return num, err
}

func UpdateCvrfFileName(afl *SaFileList, fields ...string) error {
	o := orm.NewOrm()
	_, err := o.Update(afl, fields...)
	return err
}

func DeleteCvrfFileName(afl *SaFileList, fields ...string) error {
	o := orm.NewOrm()
	_, err := o.Delete(afl, fields...)
	return err
}

func DeleteCvrfFileRecord() {
	o := orm.NewOrm()
	err := o.Raw("delete from cve_sa_file_record ").QueryRow()
	logs.Info("DeleteCvrfFileRecord", err)
}

func InsertCvrfFileRecord(afl *SaFileRecord) (int64, error) {
	o := orm.NewOrm()
	num, err := o.Insert(afl)
	return num, err
}

func QueryCvrfFileRecord(afl *SaFileRecord, colName ...string) error {
	o := orm.NewOrm()
	err := o.Read(afl, colName...)
	return err
}

func GetCvrfSaRecordByCve(cveNum, branch string) (afl []CvrfSaRecord) {
	o := orm.NewOrm()
	curCveNum := "%" + cveNum + "%"
	curBranch := "%" + branch + "%"
	sql := fmt.Sprintf("SELECT sort_openeuler_sa_num FROM cve_cvrf_sa_record where cve_num like '%v' and branch like '%v'", curCveNum, curBranch)
	num, err := o.Raw(sql).QueryRows(&afl)
	if err == nil {
		logs.Info("cve_cvrf_sa_record nums: ", num)
	} else {
		logs.Error("cve_cvrf_sa_record, err: ", err)
	}
	return afl
}
